package com.aikon.wht.concurrent;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestOfConcurrent {

	static class Buffer {

		Logger logger = LoggerFactory.getLogger(this.getClass());

		Object[] buffer = new Object[100];

		Lock lock = new ReentrantLock();

		Condition notFull = lock.newCondition();

		Condition notEmpty = lock.newCondition();

		int cnt,putIdx,takeIdx;

		public void put(Object obj) throws InterruptedException {
			lock.lock();
			while (cnt == buffer.length) {
				logger.info("NotFull await.");
				notFull.await();
			}
			try {
				buffer[putIdx] = obj;
				++putIdx;
				++cnt;
				notEmpty.signal();
				logger.info(Thread.currentThread().getName() + "   " + cnt);
				logger.info("NotEmpty signal.");
			} finally {
				lock.unlock();
			}
		}

		public Object take() throws InterruptedException {
			lock.lock();
			while (cnt == 0) {
				logger.info("NotEmpty await.");
				notEmpty.await();
			}
			Object obj;
			try {
				obj = buffer[takeIdx];
				++takeIdx;
				--cnt;
				notFull.signal();
				logger.info(Thread.currentThread().getName() + "   " + cnt);
				logger.info("NotFull signal.");
			} finally {
				lock.unlock();
			}

			return obj;
		}
	}


	public static void main(String[] args) {
		ExecutorService es = Executors.newFixedThreadPool(1);
		Buffer buffer = new Buffer();
		for (int i =0 ;i<100;i++) {
			int finalI = i;
			es.execute(()->{
				Thread.currentThread().setName("Thread" + finalI);
				try {
					buffer.put(finalI);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				try {
					buffer.take();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			});
		}
	}

}
